﻿using Sustainalytics.OAuth.Services.Common;
using Sustainalytics.Portfolios.BL;
using Sustainalytics.Portfolios.BL.Exceptions;
using Sustainalytics.Portfolios.Service.ErrorCodes;
using Sustainalytics.Portfolios.Service.Models;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;

namespace Sustainalytics.Portfolios.Service.Controllers
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [RoutePrefix("api/v1/portfolios/{portfolioName}/matches")]
    public class PortfolioMatchesController : ApiController
    {
        private readonly IPortfolioReadHandler _portfolioReadHandler;

        private readonly ICustomPortfolioUpdateHandler _portfolioUpdateHandler;

        private readonly PortfolioUserClaimsProcessor _userClaimsProcessor;        

        private EventLog _eventLog;
        private PerformanceCounter _counter;

        public PortfolioMatchesController(
            IPortfolioReadHandler portfolioReadHandlerManagement,
            ICustomPortfolioUpdateHandler portfolioUpdateHandler,
            PortfolioUserClaimsProcessor userClaimsProcessor)
        {
            this._portfolioReadHandler = portfolioReadHandlerManagement;
            this._portfolioUpdateHandler = portfolioUpdateHandler;
            this._userClaimsProcessor = userClaimsProcessor;

            this._eventLog = new EventLog("Application");
            this._eventLog.Source = "PortfolioMatches";
            this._counter = new PerformanceCounter("Process", "% Processor Time", "Sustainalytics.Portfolios.Service", true);            
        }

        [Route("valid")]
        [HttpGet]
        public HttpResponseMessage GetValidMatches(
                        string portfolioName,
                        Guid userId,
                        [FromUri] ListOptions listOptions
                        )
        {
            long count;

            var userClaims = _userClaimsProcessor.GetPortfolioClaims();

            this._eventLog.WriteEntry("Valid - afterClaims - CPU " + this._counter.NextValue());

            var portfolioMatches = this._portfolioReadHandler.GetMatchedPortfolioSecurities(
                portfolioName,
                userId,
                out count,
                listOptions,
                userClaims
           );

            IEnumerable<PortfolioDetailsBaseDto> potfolioMatchesList;

            potfolioMatchesList = portfolioMatches.Select(p => p.ToMatchesDto()).ToList();

            this._eventLog.WriteEntry("Valid - afterMatches - CPU " + this._counter.NextValue());

            return this.Request.CreateResponse(
                HttpStatusCode.OK,
                new { portfolioMatches = potfolioMatchesList, PortfolioCompanyCount = count });
        }

        [Route("invalid")]
        [HttpGet]
        public HttpResponseMessage GetInvalidMatches(
                        string portfolioName,
                        Guid userId,
                        [FromUri] ListOptions listOptions
                        )
        {
            long count;

            var userClaims = _userClaimsProcessor.GetPortfolioClaims();

            this._eventLog.WriteEntry("InValid - afterClaims - CPU " + this._counter.NextValue());

            var portfolioInvalidMatches = this._portfolioReadHandler.GetUnmatchedPortfolioSecurities(
                portfolioName,
                userId,
                out count,
                listOptions,
                userClaims
            );

            this._eventLog.WriteEntry("InValid - afterMatches - CPU " + this._counter.NextValue());

            return this.Request.CreateResponse(
                HttpStatusCode.OK,
                new { portfolioMatches = portfolioInvalidMatches, PortfolioCompanyCount = count });
        }

        [Route("{portfolioMatchId}")]
        public HttpResponseMessage Put(string portfolioName, [FromUri] Guid portfolioMatchId)
        {
            if (string.IsNullOrEmpty(portfolioName) || portfolioMatchId == Guid.Empty)
            {
                return this.Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            try
            {
                this._portfolioUpdateHandler.MarkPortfolioMatchAsValid(portfolioMatchId);
            }
            catch (Exception)
            {
                return this.Request.CreateResponse(
                                    HttpStatusCode.InternalServerError,
                                    new { ErrorCode = PortfoliosErrorCodes.PortfolioCompanyInsertUnauthorised });
            }

            return this.Request.CreateResponse(HttpStatusCode.OK);
        }

        [Route("renamePortfolioMatches/{newPortfolioName}")]
        [HttpPost]
        public HttpResponseMessage RenamePortfolioMatches(string portfolioName, [FromUri] string newPortfolioName)
        {
            if (string.IsNullOrEmpty(portfolioName) || string.IsNullOrEmpty(newPortfolioName))
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            var userClaims = _userClaimsProcessor.GetPortfolioClaims();

            this._portfolioUpdateHandler.RenamePortfolioMatches(portfolioName,newPortfolioName,userClaims);

            return Request.CreateResponse(HttpStatusCode.OK);
        }

        [Route("addCompany/{companyId}")]
        [HttpPost]
        public HttpResponseMessage AddSearchedCompanyToMatches(string portfolioName, [FromUri] Guid companyId)
        {
            if(portfolioName.IsNullOrEmpty() || companyId == Guid.Empty)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            try
            {
                var userClaims = _userClaimsProcessor.GetPortfolioClaims();

                this._portfolioUpdateHandler.AddSearchedCompany(companyId, portfolioName, userClaims);

                return this.Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (PortfolioSecurityAlreadyMatchedException)
            {
                return Request.CreateResponse(HttpStatusCode.OK, new { WarningCode = PortfoliosErrorCodes.PortfolioSecurityAlreadyMatched });
            }
            catch(PortfolioCompanyInvalidMatchException)
            {
                return this.Request.CreateResponse(HttpStatusCode.OK, new { WarningCode = PortfoliosErrorCodes.PortfolioCompanyInvalidMatch });
            }
        }

        [Route("deleteSelectedMatches")]
        [HttpPut]
        public HttpResponseMessage DeleteSelectedMatches(SelectedMatchesDto data)
        {
            var ids = data.PortfolioMatchIds;

            this._portfolioUpdateHandler.RemoveSelectedPortfolioMatches(ids);

            return this.Request.CreateResponse(HttpStatusCode.OK);
        }

        [Route("deleteAllMatches")]
        [HttpDelete]
        public HttpResponseMessage DeleteAllMatches(string portfolioName)
        {
            var userClaims = _userClaimsProcessor.GetPortfolioClaims();

            this._portfolioUpdateHandler.RemoveAllPortfolioMatches(portfolioName, userClaims.UserId, userClaims.AccountId);

            return this.Request.CreateResponse(HttpStatusCode.OK);
        }
    }
}
